package main

import (
	"fmt"
	"io"
	"os"

	"gopkg.in/yaml.v2"
)

var (
	DefaultConfig = GloablConfig{
		DnsOrgConfig: DnsOrgConfig{
			Aliyun: AliyunConfig{
				Region:       DefaultAliyunRegion,
				AccessKeyId:  "xxx",
				AccessSecret: "xxx",
			},
		},
		GetIPConfig: GetIPConfig{
			SwithMode: GETIPMODE_PUBLIC_URL,
			Cdma: GetCdmaUrlApi{
				Url:      DefaultCDMAUrl,
				Username: DefaultCDMAUser,
				Password: DefaultCDMAPWD,
			},
			PublicUrl: PublicUrl{
				Url: DefaultPublicUrl,
			},
			Ethernet: Ethernet{
				Device: "eth0",
				Num:    1,
			},
		},
	}
)

var (
	//
	DefaultAliyunRegion = "cn-hangzhou"
	//
	DefaultCDMAUrl  = "http://192.168.1.1/cgi-bin/luci"
	DefaultCDMAUser = "admin"
	DefaultCDMAPWD  = "admin"
	//
	DefaultPublicUrl = "http://ifconfig.me/ip"
)

type GloablConfig struct {
	DnsOrgConfig DnsOrgConfig `yaml:"dns_org_config"`
	GetIPConfig  GetIPConfig  `yaml:"get_ip_config"`
}

type DnsOrgConfig struct {
	DnsOrg    DNSORG       `yaml:"dns_org"`
	SubDomain string       `yaml:"sub_domain"`
	Aliyun    AliyunConfig `yaml:"aliyun,omitempty"`
}

type AliyunConfig struct {
	Region       string `yaml:"region,omitempty"`
	AccessKeyId  string `yaml:"access_key_id,omitempty"`
	AccessSecret string `yaml:"access_secret,omitempty"`
}

type GetIPConfig struct {
	SwithMode GETIPMODE     `yaml:"swith_mode"`
	Cdma      GetCdmaUrlApi `yaml:"cdma,omitempty"`
	PublicUrl PublicUrl     `yaml:"public_url,omitempty"`
	Ethernet  Ethernet      `yaml:"ethernet,omitempty"`
}

type PublicUrl struct {
	Url string `yaml:"url"`
}

type GetCdmaUrlApi struct {
	Url      string `yaml:"url"`
	Username string `yaml:"user"`
	Password string `yaml:"pwd"`
}

type Ethernet struct {
	Device string `yaml:"device"`
	Num    int    `yaml:"num"`
}

type DNSORG string

const (
	AliDNS DNSORG = "aliyun"
)

type GETIPMODE string

const (
	GETIPMODE_CDMA       GETIPMODE = "cdma"
	GETIPMODE_PUBLIC_URL GETIPMODE = "public-url"
	GETIPMODE_ETHERNET   GETIPMODE = "ethernet"
)

func (c GloablConfig) String() string {
	b, err := yaml.Marshal(c)
	if err != nil {
		return fmt.Sprintf("<error creating config string: %s>", err)
	}
	return string(b)
}

func (c *GloablConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
	*c = GloablConfig{}
	type plain GloablConfig
	if err := unmarshal((*plain)(c)); err != nil {
		return err
	}

	return nil
}

func LoadFile(filename string) (*GloablConfig, error) {

	cfg, err := loadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("parsing YAML file %s: %w", filename, err)
	}
	DefaultConfig = *cfg
	return cfg, nil
}

func loadFile(filename string) (*GloablConfig, error) {
	content, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	cfg, err := Load(string(content))
	if err != nil {
		return nil, fmt.Errorf("parsing YAML file %s: %w", filename, err)
	}

	return cfg, nil
}

func Load(s string) (*GloablConfig, error) {
	cfg := &GloablConfig{}
	//cfg = DefaultConfig
	err := yaml.UnmarshalStrict([]byte(s), cfg)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func createConfigFile(path string) error {
	cfg := DefaultConfig.String()
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer file.Close()
	_, err = io.WriteString(file, cfg)
	if err != nil {
		return err
	}
	return nil
}
